﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Line = System.Windows.Shapes.Line;

namespace SuperFrame.Charts
{
    public class ContainerAxisCrossLines : Panel
    {
        public ContainerAxisCrossLines()
        {
            this.SizeChanged += AxisCrossLinesContainer_SizeChanged;
        }

        void AxisCrossLinesContainer_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Refresh();
        }


        List<Line> xLines;
        List<Line> yLines;
        List<Line> xMinorLines;
        List<Line> yMinorLines;
        bool isInitialized;

        public void Refresh()
        {
            if (!isInitialized)
                Initialize();
            else
                Update();
        }

        private void Update()
        {

            #region ------------------------X轴--------------------------------
            if (this.XAxis.Type != XType.String)
            {
                double xAxisWidthStep = (int)this.ActualWidth / this.XAxis.IntervalCount;
                double xAxisWidthPosition = xAxisWidthStep;
                int xminorCount = 0;
                if ((this.XAxis.m_Labels.Count) == xLines.Count)
                {
                    for (int i = 0; i < this.XAxis.m_Labels.Count; i++)
                    {
                        Line line = xLines[i];
                        line.X1 = xAxisWidthPosition;
                        line.X2 = xAxisWidthPosition;
                        line.Y2 = (int)this.ActualHeight;
                        if (i != (this.XAxis.m_Labels.Count - 1))
                        {
                            for (int a = 0; a < this.XAxis.MinorTicksCount; a++)
                            {
                                Line minorline = xMinorLines[xminorCount];
                                minorline.X1 = this.XAxis.DataToPoint((this.XAxis.m_startValue + (this.XAxis.m_Interval * i)) + ((this.XAxis.m_Interval / (this.XAxis.MinorTicksCount + 1)) * (a + 1)));
                                minorline.X2 = this.XAxis.DataToPoint((this.XAxis.m_startValue + (this.XAxis.m_Interval * i)) + ((this.XAxis.m_Interval / (this.XAxis.MinorTicksCount + 1)) * (a + 1)));
                                minorline.Y1 = 0;
                                minorline.Y2 = this.ActualHeight;
                                xminorCount++;
                            }
                        }
                        xAxisWidthPosition += xAxisWidthStep;
                    }
                }
                else
                {
                    if ((this.XAxis.m_Labels.Count) > xLines.Count)
                    {
                        int offset = (this.XAxis.m_Labels.Count) - xLines.Count;
                        for (int j = 0; j < offset; j++)
                        {
                            Line line = xLines[this.XAxis.m_Labels.Count - offset - 1];
                            line.X1 = 0;
                            line.X2 = 0;
                            line.Y2 = this.ActualHeight;
                            line.SetResourceReference(Line.StyleProperty, "CrossLineStyle");
                            Binding showCrossLines = new Binding();
                            showCrossLines.Path = new PropertyPath("ShowCrossLines");
                            showCrossLines.Source = this.XAxis;
                            showCrossLines.Converter = new BooleanToVisibilityConverter();
                            line.SetBinding(Line.VisibilityProperty, showCrossLines);
                            for (int a = 0; a < this.XAxis.MinorTicksCount; a++)
                            {
                                Line minorline = new Line();
                                minorline.SetResourceReference(Line.StyleProperty, "MinorCrossLineStyle");
                                Binding minorshowCrossLines = new Binding();
                                minorshowCrossLines.Path = new PropertyPath("ShowMinorCrossLines");
                                minorshowCrossLines.Source = this.XAxis;
                                minorshowCrossLines.Converter = new BooleanToVisibilityConverter();
                                minorline.SetBinding(Line.VisibilityProperty, minorshowCrossLines);
                                minorline.X1 = this.XAxis.DataToPoint((this.XAxis.m_startValue + (this.XAxis.m_Interval * j)) + ((this.XAxis.m_Interval / (this.XAxis.MinorTicksCount + 1)) * (a + 1)));
                                minorline.X2 = this.XAxis.DataToPoint((this.XAxis.m_startValue + (this.XAxis.m_Interval * j)) + ((this.XAxis.m_Interval / (this.XAxis.MinorTicksCount + 1)) * (a + 1)));
                                minorline.Y1 = 0;
                                minorline.Y2 = this.ActualHeight;
                                this.Children.Add(minorline);
                                xMinorLines.Add(minorline);
                            }
                            this.Children.Add(line);
                            xLines.Add(line);
                        }

                    }
                    else
                    {
                        int offset = xLines.Count - (this.XAxis.m_Labels.Count);
                        for (int j = 0; j < offset; j++)
                        {
                            for (int a = 0; a < this.XAxis.MinorTicksCount; a++)
                            {
                                this.Children.Remove(xMinorLines[xMinorLines.Count - 1]);
                                xMinorLines.RemoveAt(xMinorLines.Count - 1);
                            }
                            this.Children.Remove(xLines[xLines.Count - 1]);
                            xLines.RemoveAt(xLines.Count - 1);
                        }
                    }
                    for (int i = 0; i < this.XAxis.m_Labels.Count; i++)
                    {
                        Line line = xLines[i];
                        line.X1 = xAxisWidthPosition;
                        line.X2 = xAxisWidthPosition;
                        line.Y2 = this.ActualHeight;
                        if (i != (this.XAxis.m_Labels.Count - 1))
                        {
                            for (int a = 0; a < this.XAxis.MinorTicksCount; a++)
                            {
                                Line minorline = xMinorLines[xminorCount];
                                minorline.X1 = this.XAxis.DataToPoint((this.XAxis.m_startValue + (this.XAxis.m_Interval * i)) + ((this.XAxis.m_Interval / (this.XAxis.MinorTicksCount + 1)) * (a + 1)));
                                minorline.X2 = this.XAxis.DataToPoint((this.XAxis.m_startValue + (this.XAxis.m_Interval * i)) + ((this.XAxis.m_Interval / (this.XAxis.MinorTicksCount + 1)) * (a + 1)));
                                minorline.Y1 = 0;
                                minorline.Y2 = this.ActualHeight;
                                xminorCount++;
                            }
                        }
                        xAxisWidthPosition += xAxisWidthStep;
                    }
                }
            }
            #endregion

            #region ------------------------Y轴--------------------------------
            double yAxisHeightStep = (int)this.ActualHeight / this.YAxis.IntervalCount;
            double yAxisHeightPosition = yAxisHeightStep;
            int yminorCount = 0;
            if (YAxis.m_Labels.Count == yLines.Count)
            {
                for (int i = 0; i < YAxis.m_Labels.Count; i++)
                {
                    Line line = yLines[i];
                    line.X2 = this.ActualWidth;
                    line.Y1 = yAxisHeightPosition;
                    line.Y2 = yAxisHeightPosition;
                    if (i != (this.YAxis.m_Labels.Count - 1))
                    {
                        for (int a = 0; a < this.YAxis.MinorTicksCount; a++)
                        {
                            Line minorline = yMinorLines[yminorCount];
                            minorline.Y1 = this.YAxis.DataToPoint((this.YAxis.m_startValue + (this.YAxis.m_Interval * i)) + ((this.YAxis.m_Interval / (this.YAxis.MinorTicksCount + 1)) * (a + 1)));
                            minorline.Y2 = this.YAxis.DataToPoint((this.YAxis.m_startValue + (this.YAxis.m_Interval * i)) + ((this.YAxis.m_Interval / (this.YAxis.MinorTicksCount + 1)) * (a + 1)));
                            minorline.X1 = 0;
                            minorline.X2 = this.ActualWidth;
                            yminorCount++;
                        }
                    }
                    yAxisHeightPosition += yAxisHeightStep;
                }
            }
            else
            {
                if ((this.YAxis.m_Labels.Count) > yLines.Count)
                {
                    int offset = (this.YAxis.m_Labels.Count - 2) - yLines.Count;
                    for (int j = 0; j < offset; j++)
                    {
                        Line line = new Line();
                        line.X1 = 0;
                        line.X2 = this.ActualWidth;
                        line.Y1 = yAxisHeightPosition;
                        line.Y2 = yAxisHeightPosition;
                        Binding showCrossLines = new Binding();
                        showCrossLines.Path = new PropertyPath("ShowCrossLines");
                        showCrossLines.Source = this.YAxis;
                        showCrossLines.Converter = new BooleanToVisibilityConverter();
                        line.SetBinding(Line.VisibilityProperty, showCrossLines);
                        line.SetResourceReference(Line.StyleProperty, "CrossLineStyle");
                        for (int a = 0; a < this.YAxis.MinorTicksCount; a++)
                        {
                            Line minorline = new Line();
                            minorline.SetResourceReference(Line.StyleProperty, "MinorCrossLineStyle");
                            Binding minorshowCrossLines = new Binding();
                            minorshowCrossLines.Path = new PropertyPath("ShowMinorCrossLines");
                            minorshowCrossLines.Source = this.YAxis;
                            minorshowCrossLines.Converter = new BooleanToVisibilityConverter();
                            minorline.SetBinding(Line.VisibilityProperty, minorshowCrossLines);
                            minorline.Y1 = this.YAxis.DataToPoint((this.YAxis.m_startValue + (this.YAxis.m_Interval * j)) + ((this.YAxis.m_Interval / (this.YAxis.MinorTicksCount + 1)) * (a + 1)));
                            minorline.Y2 = this.YAxis.DataToPoint((this.YAxis.m_startValue + (this.YAxis.m_Interval * j)) + ((this.YAxis.m_Interval / (this.YAxis.MinorTicksCount + 1)) * (a + 1)));
                            minorline.X1 = 0;
                            minorline.X2 = this.ActualWidth;
                            this.Children.Add(minorline);
                            yMinorLines.Add(minorline);
                        }
                        this.Children.Add(line);
                        this.yLines.Add(line);
                    }
                }
                else
                {
                    int offset = yLines.Count - (this.YAxis.m_Labels.Count);
                    for (int j = 0; j < offset; j++)
                    {
                        for (int a = 0; a < this.YAxis.MinorTicksCount; a++)
                        {
                            this.Children.Remove(yMinorLines[yMinorLines.Count - 1]);
                            yMinorLines.RemoveAt(yMinorLines.Count - 1);
                        }
                        this.Children.Remove(yLines[yLines.Count - 1]);
                        yLines.RemoveAt(yLines.Count - 1);
                    }
                }
                for (int i = 0; i < YAxis.m_Labels.Count; i++)
                {
                    Line line = yLines[i];
                    line.X2 = this.ActualWidth;
                    line.Y1 = yAxisHeightPosition;
                    line.Y2 = yAxisHeightPosition;
                    if (i != (this.YAxis.m_Labels.Count - 1))
                    {
                        for (int a = 0; a < this.YAxis.MinorTicksCount; a++)
                        {
                            Line minorline = yMinorLines[yminorCount];
                            minorline.Y1 = this.YAxis.DataToPoint((this.YAxis.m_startValue + (this.YAxis.m_Interval * i)) + ((this.YAxis.m_Interval / (this.YAxis.MinorTicksCount + 1)) * (a + 1)));
                            minorline.Y2 = this.YAxis.DataToPoint((this.YAxis.m_startValue + (this.YAxis.m_Interval * i)) + ((this.YAxis.m_Interval / (this.YAxis.MinorTicksCount + 1)) * (a + 1)));
                            minorline.X1 = 0;
                            minorline.X2 = this.ActualWidth;
                            yminorCount++;
                        }
                    }
                    yAxisHeightPosition += yAxisHeightStep;
                }
            }
            #endregion
        }
        private void Initialize()
        {
            this.Children.Clear();
            if (this.ActualHeight > 0 && this.ActualWidth > 0)
            {
                double xAxisWidthStep = this.ActualWidth / this.XAxis.IntervalCount;
                double xAxisWidthPosition = 0;
                xLines = new List<Line>();
                yLines = new List<Line>();
                xMinorLines = new List<Line>();
                yMinorLines = new List<Line>();
                int k = 0;
                for (int i = 0; i < this.XAxis.m_Labels.Count; i++)
                {
                    Line line = new Line();
                    line.X1 = this.XAxis.DataToPoint(this.XAxis.m_startValue + (this.XAxis.m_Interval * k));
                    line.X2 = this.XAxis.DataToPoint(this.XAxis.m_startValue + (this.XAxis.m_Interval * k));
                    line.Y1 = 0;
                    line.Y2 = this.ActualHeight;
                    line.SetResourceReference(Line.StyleProperty, "CrossLineStyle");
                    Binding showCrossLines = new Binding();
                    showCrossLines.Path = new PropertyPath("ShowCrossLines");
                    showCrossLines.Source = this.XAxis;
                    showCrossLines.Converter = new BooleanToVisibilityConverter();
                    line.SetBinding(Line.VisibilityProperty, showCrossLines);
                    if (i != (this.XAxis.m_Labels.Count - 1))
                    {
                        for (int a = 0; a < this.XAxis.MinorTicksCount; a++)
                        {
                            Line minorline = new Line();
                            minorline.SetResourceReference(Line.StyleProperty, "MinorCrossLineStyle");
                            Binding minorshowCrossLines = new Binding();
                            minorshowCrossLines.Path = new PropertyPath("ShowMinorCrossLines");
                            minorshowCrossLines.Source = this.XAxis;
                            minorshowCrossLines.Converter = new BooleanToVisibilityConverter();
                            minorline.SetBinding(Line.VisibilityProperty, minorshowCrossLines);
                            minorline.X1 = this.XAxis.DataToPoint((this.XAxis.m_startValue + (this.XAxis.m_Interval * k)) + ((this.XAxis.m_Interval / (this.XAxis.MinorTicksCount + 1)) * (a + 1)));
                            minorline.X2 = this.XAxis.DataToPoint((this.XAxis.m_startValue + (this.XAxis.m_Interval * k)) + ((this.XAxis.m_Interval / (this.XAxis.MinorTicksCount + 1)) * (a + 1)));
                            minorline.Y1 = 0;
                            minorline.Y2 = this.ActualHeight;
                            this.Children.Add(minorline);
                            xMinorLines.Add(minorline);
                        }
                    }
                    xLines.Add(line);
                    this.Children.Add(line);
                    xAxisWidthPosition += xAxisWidthStep;
                    k++;
                }
                double yAxisHeightStep = this.ActualHeight / this.YAxis.IntervalCount;
                double yAxisHeightPosition = 0;
                int j = 0;
                for (int i = 0; i < YAxis.m_Labels.Count; i++)
                {
                    Line line = new Line();
                    line.X1 = 0;
                    line.X2 = this.ActualWidth;
                    line.Y1 = this.YAxis.DataToPoint(this.YAxis.m_startValue + (this.YAxis.m_Interval * j));
                    line.Y2 = this.YAxis.DataToPoint(this.YAxis.m_startValue + (this.YAxis.m_Interval * j));
                    Binding showCrossLines = new Binding();
                    showCrossLines.Path = new PropertyPath("ShowCrossLines");
                    showCrossLines.Source = this.YAxis;
                    showCrossLines.Converter = new BooleanToVisibilityConverter();
                    line.SetBinding(Line.VisibilityProperty, showCrossLines);
                    line.SetResourceReference(Line.StyleProperty, "CrossLineStyle");
                    if (i != (this.YAxis.m_Labels.Count - 1))
                    {
                        for (int a = 0; a < this.YAxis.MinorTicksCount; a++)
                        {
                            Line minorline = new Line();
                            minorline.SetResourceReference(Line.StyleProperty, "MinorCrossLineStyle");
                            Binding minorshowCrossLines = new Binding();
                            minorshowCrossLines.Path = new PropertyPath("ShowMinorCrossLines");
                            minorshowCrossLines.Source = this.YAxis;
                            minorshowCrossLines.Converter = new BooleanToVisibilityConverter();
                            minorline.SetBinding(Line.VisibilityProperty, minorshowCrossLines);
                            minorline.Y1 = this.YAxis.DataToPoint((this.YAxis.m_startValue + (this.YAxis.m_Interval * j)) + ((this.YAxis.m_Interval / (this.YAxis.MinorTicksCount + 1)) * (a + 1)));
                            minorline.Y2 = this.YAxis.DataToPoint((this.YAxis.m_startValue + (this.YAxis.m_Interval * j)) + ((this.YAxis.m_Interval / (this.YAxis.MinorTicksCount + 1)) * (a + 1)));
                            minorline.X1 = 0;
                            minorline.X2 = this.ActualWidth;
                            this.Children.Add(minorline);
                            yMinorLines.Add(minorline);
                        }
                    }
                    this.Children.Add(line);
                    this.yLines.Add(line);
                    yAxisHeightPosition += yAxisHeightStep;
                    j++;
                }
                isInitialized = true;
            }
        }

        public XAxis XAxis
        {
            get { return (XAxis)GetValue(XAxisProperty); }
            set { SetValue(XAxisProperty, value); }
        }
        public static readonly DependencyProperty XAxisProperty = DependencyProperty.Register("XAxis", typeof(XAxis), typeof(ContainerAxisCrossLines), new PropertyMetadata(null));

        public YAxis YAxis
        {
            get { return (YAxis)GetValue(YAxisProperty); }
            set { SetValue(YAxisProperty, value); }
        }
        public static readonly DependencyProperty YAxisProperty = DependencyProperty.Register("YAxis", typeof(YAxis), typeof(ContainerAxisCrossLines), new PropertyMetadata(null));

        protected override Size ArrangeOverride(Size finalSize)
        {
            foreach (UIElement child in Children)
            {
                child.Arrange(new Rect(new Point(0, 0), finalSize));
            }
            return finalSize;
        }
        protected override Size MeasureOverride(Size availableSize)
        {
            Size desiredSize = new Size(0, 0);
            foreach (UIElement child in Children)
            {
                child.Measure(availableSize);
                desiredSize.Width += child.DesiredSize.Width;
                desiredSize.Height += child.DesiredSize.Height;
            }
            if (Double.IsInfinity(availableSize.Height))
                availableSize.Height = desiredSize.Height;
            if (Double.IsInfinity(availableSize.Width))
                availableSize.Width = desiredSize.Width;
            return availableSize;
        }
    }
}
